#include "gkt_os.h"
#include "gkt_gpio.h"
#include "gkt_debug.h"
#include "gkt_indoor_bell.h"

#if defined(GKT_CONFIG_INDOOR_BELL_ENABLE) && GKT_CONFIG_INDOOR_BELL_ENABLE \
	&& (GKT_MODULE_LOC_FRONTBOARD == INDOOR_BELL_LOCATION) \
	&& (INDOOR_BELL_DRVIC_AC8DD12 == INDOOR_BELL_DRVIC)

#ifndef GKT_CONFIG_INDOOR_BELL_GPIO_PIN
#error "not define GKT_CONFIG_INDOOR_BELL_GPIO_PIN."
#endif

#define INDOOR_BELL_SYNC_TIME_MS	50
#define INDOOR_BELL_ACTIVE_TIME_MS	50
#define INDOOR_BELL_DURATION_MS	2600

enum {
	INDOOR_BELL_ST_IDLE = 0,
	INDOOR_BELL_ST_REQUEST,
	INDOOR_BELL_ST_ACTIVE,
	INDOOR_BELL_ST_MAX
};

typedef struct {
	int	init_ok;
	gkt_indoor_bell_notify	notify;

	uint32_t	state;
	gkt_mutex_t	mutex;
	gkt_soft_timer_t	timer_id;
} indoor_bell_fb_s;
static indoor_bell_fb_s s_indoor_bell_fb;

static int indoor_bell_set_timer(uint32_t time_ms)
{
	int retval;

	retval = gkt_soft_timer_start(s_indoor_bell_fb.timer_id, time_ms);
	if (retval != GKT_SUCCESS) {
		gkt_gpio_set_pin_level(GKT_CONFIG_INDOOR_BELL_GPIO_PIN, 0);
		s_indoor_bell_fb.state = INDOOR_BELL_ST_IDLE;
	}

	return retval;
}

static void indoor_bell_timer_callback(void *params)
{
	int retval;

	retval = gkt_mutex_lock(s_indoor_bell_fb.mutex, 
				INDOOR_BELL_SYNC_TIME_MS);
	if (GKT_SUCCESS == retval) {
		if (INDOOR_BELL_ST_REQUEST == s_indoor_bell_fb.state) {
			s_indoor_bell_fb.state = INDOOR_BELL_ST_ACTIVE;
			gkt_mutex_unlock(s_indoor_bell_fb.mutex);

			gkt_gpio_set_pin_level(GKT_CONFIG_INDOOR_BELL_GPIO_PIN, 0);
			indoor_bell_set_timer(INDOOR_BELL_DURATION_MS);
		}
		else if (INDOOR_BELL_ST_ACTIVE == s_indoor_bell_fb.state) {
			s_indoor_bell_fb.state = INDOOR_BELL_ST_IDLE;
			gkt_mutex_unlock(s_indoor_bell_fb.mutex);

			if (s_indoor_bell_fb.notify)
				(*s_indoor_bell_fb.notify)(GKT_INDOOR_BELL_ST_PLAY_END);
		}
		else {
			gkt_mutex_unlock(s_indoor_bell_fb.mutex);
			gkt_error("indoor_bell_timer_callback: invalid state(%u)\n",
				s_indoor_bell_fb.state);
		}
	}
	else
		gkt_error("indoor_bell_timer_callback: mutex sync failed %d\n", retval);
}

uint32_t gkt_indoor_bell_get_duration(void)
{
	return INDOOR_BELL_DURATION_MS;
}

int gkt_indoor_bell_play(void)
{
	int retval;

	if (!s_indoor_bell_fb.init_ok)
		return GKT_ENOTINIT;

	retval = gkt_mutex_lock(s_indoor_bell_fb.mutex, 
				INDOOR_BELL_SYNC_TIME_MS);
	if (GKT_SUCCESS == retval) {
		if (s_indoor_bell_fb.state != INDOOR_BELL_ST_IDLE) {
			gkt_mutex_unlock(s_indoor_bell_fb.mutex);
			return GKT_EINPROCESS;
		}
		s_indoor_bell_fb.state = INDOOR_BELL_ST_REQUEST;
		gkt_gpio_set_pin_level(GKT_CONFIG_INDOOR_BELL_GPIO_PIN, 1);
		gkt_mutex_unlock(s_indoor_bell_fb.mutex);

		retval = indoor_bell_set_timer(INDOOR_BELL_ACTIVE_TIME_MS);
	}

	return retval;
}

void gkt_indoor_bell_stop(void)
{
	int retval;

	retval = gkt_mutex_lock(s_indoor_bell_fb.mutex, 
				INDOOR_BELL_SYNC_TIME_MS);
	if (GKT_SUCCESS == retval) {
		s_indoor_bell_fb.state = INDOOR_BELL_ST_IDLE;
		gkt_gpio_set_pin_level(GKT_CONFIG_INDOOR_BELL_GPIO_PIN, 0);
		gkt_mutex_unlock(s_indoor_bell_fb.mutex);
	}
}

void gkt_indoor_bell_register_notify(
			gkt_indoor_bell_notify notify)
{
	s_indoor_bell_fb.notify = notify;
}

int gkt_indoor_bell_init(void)
{
	int retval;

	s_indoor_bell_fb.init_ok = 0;
	s_indoor_bell_fb.notify = NULL;
	s_indoor_bell_fb.state = INDOOR_BELL_ST_IDLE;

	retval = gkt_gpio_config(GKT_CONFIG_INDOOR_BELL_GPIO_PIN,
					GKT_GPIO_F_OUTPUT | GKT_GPIO_F_PULL_DOWN, NULL);
	if (retval != GKT_SUCCESS) {
		gkt_error("inside_bell: config gpio failed!\n");
		return retval;
	}

	s_indoor_bell_fb.mutex = gkt_mutex_create(0);
	if (!s_indoor_bell_fb.mutex) {
		gkt_error("inside_bell: create mutex failed!\n");
		return GKT_ECREATE;
	}

	s_indoor_bell_fb.timer_id = gkt_soft_timer_create(GKT_SOFT_TIMER_ONCE, 
		indoor_bell_timer_callback, NULL);
	if (!s_indoor_bell_fb.timer_id) {
		gkt_error("inside_bell: create timer failed!\n");
		return GKT_ECREATE;
	}

	s_indoor_bell_fb.init_ok = 1;

	return GKT_SUCCESS;
}

#endif

